package com.atguigu.gmall.activity.consumer;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.redis.CacheHelper;
import com.atguigu.gmall.activity.util.DateUtil;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.product.client.common.constant.RedisConst;
import com.atguigu.gmall.product.client.model.activity.SeckillGoods;
import com.atguigu.gmall.product.client.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;

import java.util.Date;
import java.util.List;

//秒杀消息通知
@Component
public class activityConsumer {


    @Autowired
    private SeckillGoodsMapper seckillGoodMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    //半夜12点接收消息
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = MqConst.ROUTING_TASK_1))
    public void secKillImportRedis(Message message, Channel channel){
        try {
            //将秒杀表的数据导入缓存  当天的

            //4. 查询  (1 2 3是秒杀的必要条件)
            QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<>();
            //1. 审核通过的商品 才能秒杀
            queryWrapper.eq("status",1);
            //2. 当天商品   才能秒杀
            queryWrapper.gt("stock_count",0);
            //3. 必须有剩余库存的商品 才能秒杀
            queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')",
                    DateUtil.formatDate(new Date()));
            //Date time = Calendar.getInstance().getTime(); //也是创建当前时间  和new Date()是一样的 但是比new Date()精准
            List<SeckillGoods> seckillGoodsList = seckillGoodMapper.selectList(queryWrapper);
            if (!CollectionUtils.isEmpty(seckillGoodsList)){   //CollectionUtils.isEmpty    判断集合是否为空  返回为true
                                                                // StringUtils.isEmpty()    判断字符串是否为空 返回为true 或者 null
                //有秒杀商品
                seckillGoodsList.forEach(seckillGoods -> {
                    //5. 将结果集保存到redis缓存中   (考虑 使用redis五大数据类型中哪个类型)
                    //hash类型 h hk hv
                    //5.1 判断缓存是否存在
                    if (!redisTemplate.opsForHash().hasKey(
                            RedisConst.SECKILL_GOODS,   //  常量  秒杀的前缀
                            seckillGoods.getSkuId().toString()   //商品的id  在转为字符串
                    )){
                        //作为新秒杀商品保存到缓存中
                        redisTemplate.opsForHash().put(
                                RedisConst.SECKILL_GOODS,  //  常量  秒杀的前缀
                                seckillGoods.getSkuId().toString(),   //商品的id  在转为字符串
                                seckillGoods);     //秒杀商品的对象
                        //6. 防止超卖   秒杀商品放到货架
                        redisTemplate.opsForList().leftPushAll(
                                RedisConst.SECKILL_STOCK_PREFIX + seckillGoods.getSkuId(),
                                buildSkuIds(seckillGoods.getSkuId(),seckillGoods.getStockCount()));
                        //7. 状态位   每一款商品都要有状态位
                        redisTemplate.convertAndSend("seckillpush",
                                seckillGoods.getSkuId() + "1");
                    }
                });
            }


            //接收消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = MqConst.ROUTING_SECKILL_USER))
    public void secKill(UserRecode userRecode,Message message, Channel channel){
        try {

            //1. 校验状态位
            Object status = CacheHelper.get(userRecode.getUserId().toString());
            if (!"1".equals(status)){  //如果没有状态位 就证明已经失败了  直接返回
                return;
            }

            //2. 用户是否来过
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(
                    RedisConst.SECKILL_USER + userRecode.getUserId(),
                    "1");
            if (!flag){
                //来过
                return;
            }

            //3. redis leftpop
            String skuId = (String) redisTemplate.opsForList().rightPop(
                    RedisConst.SECKILL_STOCK_PREFIX + userRecode.getSkuId());
            if (null == skuId){
                //4. 没有  修改状态位
                redisTemplate.convertAndSend(
                        "seckillpush",
                        userRecode.getSkuId() + "0");
                return;
            }

            //5. 有  将资格保存在redis
            redisTemplate.opsForValue().set(
                    RedisConst.SECKILL_ORDERS + userRecode.getUserId(),
                    userRecode.getSkuId());
            //6. 收尾!  更下一下库存.....没有写

            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    //数组 string[] ids = {skuId,skuId,skuId}
    public String[] buildSkuIds(Long skuId,Integer stock){

        String[] ids = new String[stock];
        for (int i = 0; i <stock; i++) {
            ids[i] = skuId.toString();
        }
        return ids;
    }

}
